#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<sys/select.h>

#define SERVERPORT 8001
#define BUFSIZE 1024


int main(int argc, char* argv[])
{
    // 创建套接字
    int lfd = socket(AF_INET,SOCK_STREAM,0);
    if(lfd == -1)
    {
        perror("socket error");
        exit(1);
    }

    struct sockaddr_in seraddr,cliaddr;
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(SERVERPORT);
    seraddr.sin_addr.s_addr = 0;
    // 绑定IP和端口
    bind(lfd,(struct sockaddr*)&seraddr,sizeof(seraddr));
    // 主动套接字转被动套接字
    listen(lfd,64);
    printf("等待客户端建立连接\n");
    
    char buf[BUFSIZE];

    fd_set read_set,all_set;
    FD_ZERO(&all_set); // 初始化位图 所有位置 0
    FD_SET(lfd,&all_set); // 把某个为置 1 将lfd放入数组中
    int nfds = lfd + 1; // nfds等于最大描述符加1

    while(1)
    {
        read_set = all_set; // 生成副本
        int sret = select(nfds,&read_set,NULL,NULL,NULL);
        if(sret == -1)
        {
            perror("select error");
            exit(1);
        }

        if(FD_ISSET(lfd,&read_set))
        {
            // 读事件触发，马上处理
            printf("事件触发，马上处理\n");
            int caddrlen = sizeof(cliaddr);
            int cfd = accept(lfd,(struct sockaddr*)&cliaddr,&caddrlen);
            if(cfd == -1)
            {
                perror("accept error");
                exit(1);
            }
            // 取出客户端端口号
            int port = ntohs(cliaddr.sin_port);
            // 取出客户端ip
            char dst[64];
            inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,dst,sizeof(dst));
            printf("客户端%s 建立连接,端口号为：%d\n",dst,port);

            if(cfd > 1023)
            {
                printf("too many client");
                exit(1);
            }
            FD_SET(cfd,&all_set); // 将cfd放入位图中
            if(cfd > nfds - 1)
            {
                nfds = cfd + 1;
            }
            if(--sret == 0)
            {
                continue;
            }
        }

        for(int i = lfd + 1; i < nfds; i++)
        {
            if(FD_ISSET(i,&read_set))
            {
                int rret = read(i,buf,sizeof(buf));
                if(rret == -1)
                {
                    perror("read error");
                    exit(1);
                }
                else if(rret == 0)
                {
                    printf("客户端断开连接\n");
                    close(i);
                    FD_CLR(i,&all_set); // 将文件描述符删除监听
                }
                else 
                {
                    write(i,buf,rret);
                    write(STDOUT_FILENO,buf,rret);
                }
                if(--sret == 0) 
                {
                    break;
                }
            }
        }
    }



    return 0;
}



